package com.bieber.server.netty.handler;

import com.bieber.common.Constants;
import com.bieber.server.config.ServerConfig;
import com.bieber.server.exception.FileTransportException;
import com.bieber.server.pack.FilePackage;
import com.bieber.server.pack.FileStatus;
import com.bieber.server.serialize.KryoSerializer;
import com.bieber.server.serialize.Serializer;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import org.apache.commons.lang.StringUtils;

import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.List;

/**
 * Created by bieber on 2015/8/19.
 */
public class Decoder extends ByteToMessageDecoder {

    private static final Serializer DEFAULT_SERIALIZER = new KryoSerializer();

    private ServerConfig config;

    public Decoder(ServerConfig config) {
        this.config = config;
    }

    private FilePackage parseHead(ByteBuf in) throws UnsupportedEncodingException {
        FilePackage filePackage = new FilePackage();
        byte status = in.readByte();
        long fileSize=in.readLong();
        long offset=in.readLong();
        int fileNameLength = in.readInt();
        byte[] fileName = new byte[fileNameLength];
        in.readBytes(fileName);
        int nodeNameLength = in.readInt();
        byte[] nodeName = new byte[nodeNameLength];
        in.readBytes(nodeName);
        filePackage.setFileSize(fileSize);
        filePackage.setOffset(offset);
        filePackage.setStatus(FileStatus.valueOf(status));
        filePackage.setFileName(new String(fileName,config.getCharSet()));
        filePackage.setNodeName(new String(nodeName,config.getCharSet()));
        return filePackage;
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        //如果可读的消息大于或者等于报文头，那么对该报文解析
        //|FRAME_LENGTH(4byte)|HEAD_LENGTH(4byte)|MESSAGE_TYPE(1byte)|FILE_SIZE(8byte)|OFFSET(8byte)|FILENAME_LENGTH(4byte)|FILE_NAME|NODE_NAME_LENGTH(4byte)|NODE_NAME
        int saveReadIndex = in.readerIndex();
        if(in.readableBytes()<4){
            return ;
        }
        int totalLength = in.readInt();
        if(in.readableBytes()>= totalLength-4){
            int headLength=in.readInt();//读取头大小
            FilePackage filePackage = parseHead(in);
            out.add(filePackage);
            int body=totalLength-headLength;
            byte[] bytes =new  byte[body];
            in.readBytes(bytes);
            switch (filePackage.getStatus()){
                case START_WRITE:{

                    break;
                }
                case WRITE_CONTENT:{
                    ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length).put(bytes);
                    byteBuffer.flip();
                    filePackage.setContent(byteBuffer);
                    break;
                }
                case ERROR:{
                    filePackage.setException(DEFAULT_SERIALIZER.deSerialize(bytes, FileTransportException.class));
                    break;
                }
                case END_WRITE:{
                    //not do anything
                    break;
                }
            }
        }else{
            in.readerIndex(saveReadIndex);
        }
    }
}
